/*
 * Created on Feb 11, 2005
 * Created by dfhuynh
 */
package edu.mit.simile.longwell.query.bucket;

import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.Set;

import edu.mit.simile.SimileUtilities;
import edu.mit.simile.longwell.Cache;
import edu.mit.simile.longwell.CascadedCache;
import edu.mit.simile.longwell.Profile;
import edu.mit.simile.longwell.ProfileListenerBase;
import edu.mit.simile.longwell.query.QueryException;
import edu.mit.simile.longwell.query.project.IProjection;

/**
 * @author dfhuynh
 */
public abstract class BucketerBase extends ProfileListenerBase implements IBucketer {
	final protected Profile m_profile;
	
	protected BucketerBase(Profile profile) {
		m_profile = profile;
	}

	/* (non-Javadoc)
	 * @see edu.mit.simile.longwell.query.bucket.IBucketer#getBucket(edu.mit.simile.longwell.query.project.IProjection, java.lang.String)
	 */
	final protected CascadedCache 
		m_projectionToParameterToBucket = new CascadedCache(
			BucketerBase.class, "projection", 10, "parameter", 10);
	
	public Set getBucket(IProjection projection, String parameter) throws QueryException {
		Set bucket = (Set) m_projectionToParameterToBucket.get(projection, parameter);
		if (bucket == null || (bucket!=null && bucket.size()==0)) {
			bucket = internalGetBucket(projection, parameter);
			m_projectionToParameterToBucket.put(projection, parameter, bucket);
		}
		return bucket;
	}
	
	/* (non-Javadoc)
	 * @see edu.mit.simile.longwell.query.bucket.IBucketer#parameterToDescription(java.lang.String, java.lang.String)
	 */
	public String parameterToDescription(String parameter, String locale) {
		String[] params = splitParameter(parameter);
		String[] descriptions = new String[params.length];
		
		for (int i = 0; i < params.length; i++) {
			descriptions[i] = individualParameterToDescription(params[i], locale);
		}
		
		return concatenateListItems(descriptions);
	}
	
	/* (non-Javadoc)
	 * @see edu.mit.simile.longwell.query.bucket.IBucketer#matchesOneValue(java.lang.String)
	 */
	public boolean matchesOneValue(String parameter) {
		return splitParameter(parameter).length == 1;
	}

	/* (non-Javadoc)
	 * @see edu.mit.simile.longwell.query.bucket.IBucketer#suggestBuckets(edu.mit.simile.longwell.query.project.IProjection, float)
	 */
	final protected Cache m_projectionToNarrowingSuggestion = new Cache(10, BucketerBase.class, "projection-to-narrowing-suggestion");
	public List suggestNarrowingBuckets(IProjection projection, float desirable) {
		List suggestion = (List) m_projectionToNarrowingSuggestion.get(projection);
		if (suggestion == null || desirable == 1) {
			suggestion = internalSuggestNarrowingBuckets(projection, desirable);
			m_projectionToNarrowingSuggestion.put(projection, suggestion);
		}
		return suggestion;
	}
	
	/* (non-Javadoc)
	 * @see edu.mit.simile.longwell.query.bucket.IBucketer#suggestBroadeningBuckets(edu.mit.simile.longwell.query.project.IProjection, java.lang.String)
	 */
	final protected CascadedCache m_projectionToParameterToBroadeningSuggestion = 
		new CascadedCache(
			BucketerBase.class,
			"projection", 10,
			"parameter", 10
		);
	public BroadeningResult suggestBroadeningBuckets(
			IProjection projection, String parameter) {
		BroadeningResult result = (BroadeningResult) 
			m_projectionToParameterToBroadeningSuggestion.get(
				projection, parameter);
		if (result == null) {
			result = internalSuggestBroadeningBuckets(projection, parameter);
			m_projectionToParameterToBroadeningSuggestion.put(projection, parameter, result);
		}
		
		return result;
	}
	
	abstract protected Set 
		internalGetBucket(
			IProjection projection, String parameter);
	
	abstract protected List 
		internalSuggestNarrowingBuckets(
			IProjection projection, float desirable);
	
	abstract protected BroadeningResult
		internalSuggestBroadeningBuckets(
			IProjection projection, String parameter);
	
	abstract protected String 
		individualParameterToDescription(
			String parameter, String locale);

	protected ResourceBundle getResources(String locale) {
		return ResourceBundle.getBundle(
				this.getClass().getName(),
				locale == null ? Locale.getDefault() : new Locale(locale));
	}
	
	static protected String[] splitParameter(String s) {
		String[] params = s.split(",");
		
		for (int i = 0; i < params.length; i++) {
			params[i] = decodeParameter(params[i]);
		}
		
		return params;
	}
	
	static protected String concatenateListItems(String[] items) {
		ResourceBundle resources = 
			ResourceBundle.getBundle(BucketerBase.class.getName());
		
		if (items.length == 0) {
			return resources.getString("EmptyList");
		} else if (items.length == 1) {
			return items[0];
		} else {
			String s = resources.getString("ListLeftDelimiter");
			
			String separator = resources.getString("ListSeparator");
			
			for (int i = 0; i < items.length; i++) {
				if (i > 0) {
					s += separator;
				}
				s += items[i];
			}
			s += resources.getString("ListRightDelimiter");
			
			return s;
		}
	}
	
	static public String decodeParameter(String s) {
		return SimileUtilities.unescape(s, ',', '~', 'c');
	}
	
	static public String encodeParameter(String s) {
		return SimileUtilities.escape(s, ',', '~', 'c');
	}
}
